﻿using System.Linq;
using Raytracer.Properties;
using RaytracerLib;
using RaytracerLib.Layers;
using RaytracerLib.MathLib;
using RaytracerLib.Volumes;
using RaytracerLib.Materials;
using System;
using RaytracerLib.Layers.Interpolators;
using RaytracerLib.Layers.OverlayCorrectors;

namespace Raytracer.Generator
{
    public static class TestMaterials
    {
        public static Material CheckBoard(string a_name,
            ColorFloat a_c1, ColorFloat a_c2, double a_scale_x = 1, double a_scale_y = 1)
        {
            Material material = new Material();
            material.Name = a_name;

            material.SpecularHighlight = VolumesFactory.Solid(new ColorFloat(192 / 255.0));
            material.SpecularHighlightExponent = VolumesFactory.Solid(200);
            material.Ambient = VolumesFactory.Solid(new ColorFloat(1));

            material.Diffuse = LayersFactory.Scale(LayersFactory.Procedural(
                Resources.CheckboardScript), new Vector2(a_scale_x, a_scale_y));

            Layer.GetAllScripts(material.Diffuse as Layer).
                First().Params["Color #1"].Value = a_c1;
            Layer.GetAllScripts(material.Diffuse as Layer).
                First().Params["Color #2"].Value = a_c2;

            material.ReflectionTransmittance =
                LayersFactory.Scale(LayersFactory.Procedural(Resources.CheckboardScript),
                    new Vector2(a_scale_x, a_scale_y));

            Layer.GetAllScripts(material.ReflectionTransmittance as Layer).
                First().Params["Color #1"].Value = a_c1;
            Layer.GetAllScripts(material.ReflectionTransmittance as Layer).
                First().Params["Color #2"].Value = a_c2;

            return material;
        }

        public static Material Wood(string a_name)
        {
            Material material = Solid(a_name,
                new ColorFloat(0.9, 0.2, 0.9), 1, 0.7, 0.7, 150);
            material.Diffuse = LayersFactory.Scale(
                LayersFactory.TextureFromFile("Wood1.jpg", InterpolationMethod.Bilinear,
                    OverlayMethod.Overlap), new Vector2(8, 8 * 1854 / 2560));

            return material;
        }

        public static Material Earth(string a_name)
        {
            Material material = new Material();
            material.Name = a_name;

            Layer earth = LayersFactory.TextureFromFile(
                "Earth-Color4096.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);
            Layer clouds = LayersFactory.TextureFromFile(
                "Earth-Clouds2700.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);
            Layer spec = LayersFactory.TextureFromFile(
                "Earth-Spec4096.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);
            Layer bump = LayersFactory.TangentsFromFile(
                "Earth-Topo4096.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);

            material.Ambient = VolumesFactory.Solid(new ColorFloat(1));

            material.Diffuse = LayersFactory.Transparent(clouds, earth,
                LayersFactory.Sub(1, clouds));

            material.SpecularHighlightExponent = VolumesFactory.Solid(150);

            material.SpecularHighlight = null;

            material.ReflectionTransmittance = LayersFactory.Mul(LayersFactory.Mul(
                LayersFactory.Neg(clouds), spec), 0.1);

            material.Tangents = bump;

            return material;
        }

        public static Material EarthSimple(string a_name = null)
        {
            if (a_name == null)
                a_name = "eart_simple";

            Material material = new Material();
            material.Name = a_name;

            Layer earth = LayersFactory.TextureFromFile(
                "Earth-Color4096.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);

            material.Ambient = VolumesFactory.Solid(new ColorFloat(1));

            material.Diffuse = earth;

            return material;
        }

        public static Material Mushroom(string a_name = null)
        {
            if (a_name == null)
                a_name = "mushroom";

            Material material = new Material();
            material.Name = a_name;

            Layer mushroom = LayersFactory.TextureFromFile(
                "mushroom.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);

            material.Ambient = VolumesFactory.Solid(new ColorFloat(1));
            material.Diffuse = mushroom;

            return material;
        }

        public static Material Cone(string a_name = null)
        {
            if (a_name == null)
                a_name = "cone";

            Material material = new Material();
            material.Name = a_name;

            Layer cone = LayersFactory.TextureFromFile(
                "Cone.png", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);

            material.Ambient = VolumesFactory.Solid(new ColorFloat(1));
            material.Diffuse = cone;

            return material;
        }

        public static Material EarthBump(string a_name)
        {
            Material material = new Material();
            material.Name = a_name;

            Layer shape = LayersFactory.TextureFromFile(
                "Earth-Spec4096.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);
            Layer bump = LayersFactory.TangentsFromFile(
                "Earth-Topo4096.jpg", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);

            material.Ambient = VolumesFactory.Solid(new ColorFloat(1));

            material.Diffuse = LayersFactory.Scale(LayersFactory.Mul(LayersFactory.Neg(shape),
                new ColorFloat(0, 0, 0.6)), new Vector2(1, 1));

            material.Tangents = LayersFactory.Scale(bump, new Vector2(1, 1));

            return material;
        }

        public static Material BumpCircle(string a_name = null, double a_scale_x = 1, double a_scale_y = 1)
        {
            if (a_name == null)
                a_name = "bump_circle";

            Material material = new Material();
            material.Name = a_name;

            Layer diff = LayersFactory.TextureFromFile(
                "bump circle diff.png", InterpolationMethod.Bilinear, OverlayMethod.Overlap);
            Layer bump = LayersFactory.TangentsFromFile(
                "bump circle.png", InterpolationMethod.Bilinear, OverlayMethod.Overlap);

            material.Ambient = VolumesFactory.Solid(new ColorFloat(1));
            material.Diffuse = LayersFactory.Scale(diff, new Vector2(a_scale_x, a_scale_y));
            material.Tangents = LayersFactory.Scale(bump, new Vector2(a_scale_x, a_scale_y));
            
            return material;
        }

        public static Material Solid(string a_name, ColorFloat a_diffuse,
            double a_ambient = 1, double a_specular = 0, double a_reflect = 0,
            double a_exponent = 1)
        {
            Material material = new Material();
            material.Name = a_name;

            material.Diffuse = VolumesFactory.Solid(a_diffuse);
            material.Ambient = VolumesFactory.Solid(new ColorFloat(a_ambient));
            material.SpecularHighlight = VolumesFactory.Solid(new ColorFloat(a_specular));
            material.ReflectionTransmittance = VolumesFactory.Solid(new ColorFloat(a_reflect));
            material.SpecularHighlightExponent = VolumesFactory.Solid(a_exponent);

            return material;
        }

        public static Material Shiny(string a_name, ColorFloat a_diffuse,
            double a_ambient = 1, double a_specular = 1, double a_reflect = 1,
            double a_exponent = 150)
        {
            Material material = new Material();
            material.Name = a_name;

            material.Diffuse = VolumesFactory.Solid(a_diffuse);
            material.Ambient = VolumesFactory.Solid(new ColorFloat(a_ambient));
            material.SpecularHighlight = VolumesFactory.Solid(new ColorFloat(a_specular));
            material.ReflectionTransmittance = VolumesFactory.Solid(new ColorFloat(a_reflect));
            material.SpecularHighlightExponent = VolumesFactory.Solid(a_exponent);

            return material;
        }

        public static Material Refractive(string a_name, ColorFloat a_diffuse, bool a_mirror = false,
            double a_refractive_indice = RefractiveIndices.OpticGlass1, double a_refra = 0.9, double a_refle = 0.9)
        {
            Material material = new Material();
            material.Name = a_name;

            if (!a_mirror)
                material.Diffuse = VolumesFactory.Solid(a_diffuse);

            material.Ambient = VolumesFactory.Solid(1);
            material.RefractionTransmittance = VolumesFactory.Solid(a_refra);
            material.ReflectionTransmittance = VolumesFactory.Solid(a_refle);
            material.RefractionIndice = a_refractive_indice;
            material.SpecularHighlight = VolumesFactory.Solid(new ColorFloat(1));
            material.SpecularHighlightExponent = VolumesFactory.Solid(150);

            return material;
        }
    }
}